﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ParameterDisplayManager.h"
#include "IDocument.h"
#include "UniIdentity.h"
#include "IParameterDefinitionLibrary.h"
#include "IParameterDefinition.h"
#include "ParameterDisplayCheckbox.h"
#include "IParameterValueList.h"
#include "ParameterType.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;


namespace 
{
    std::map<UniIdentity, OwnerPtr<IParameterDisplay>>& BuiltInUidToParameterDisplayMap()
    {
        static std::map<UniIdentity, OwnerPtr<IParameterDisplay>> s_builtInUidToParameterDisplayMap;
        return s_builtInUidToParameterDisplayMap;
    }
}


gcmp::ParameterDisplayManager::ParameterDisplayManager(const IDocument* pDoc) : m_pDoc(pDoc)
{
}

gcmp::ParameterDisplayManager::~ParameterDisplayManager()
{
}

bool gcmp::ParameterDisplayManager::AddBuiltInParameterDisplay( OwnerPtr<IParameterDisplay> oParameterDisplay )
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(oParameterDisplay, L"oParameterDisplay为空！",L"GDMPLab",L"2024-03-30");

    const UniIdentity& uid = oParameterDisplay->GetParameterDefinitionUid();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(uid.IsValid(), L"无效id！",L"GDMPLab",L"2024-03-30");

    //如果该内建参数已存在，则不添加直接返回，否则添加该参数.
    //在Addin多次卸载再加载时可能会出现该情况
    auto it = BuiltInUidToParameterDisplayMap().find(uid);
    if (it != BuiltInUidToParameterDisplayMap().end())
    {
        return false;
    }

    BuiltInUidToParameterDisplayMap()[uid] = TransferOwnership(oParameterDisplay);
    return true;
}

bool gcmp::ParameterDisplayManager::ReplaceBuiltInParameterDisplay(OwnerPtr<IParameterDisplay> oParameterDisplay)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(oParameterDisplay, L"oParameterDisplay为空！",L"GDMPLab",L"2024-03-30");

    const UniIdentity& uid = oParameterDisplay->GetParameterDefinitionUid();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(uid.IsValid(), L"无效uid！",L"GDMPLab",L"2024-03-30");

    auto it = BuiltInUidToParameterDisplayMap().find(uid);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(it != BuiltInUidToParameterDisplayMap().end(), L"uid不存在！",L"GDMPLab",L"2024-03-30");

    BuiltInUidToParameterDisplayMap()[uid] = TransferOwnership(oParameterDisplay);
    return true;
}

bool gcmp::ParameterDisplayManager::AddCustomParameterDisplay(OwnerPtr<IParameterDisplay> oParameterDisplay)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(oParameterDisplay, L"无效oParameterDisplay！",L"GDMPLab",L"2024-03-30");
    const UniIdentity& uid = oParameterDisplay->GetParameterDefinitionUid();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(uid.IsValid(), L"无效uid！",L"GDMPLab",L"2024-03-30");

    auto it = m_uidToParameterDisplayMap.find(uid);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(it == m_uidToParameterDisplayMap.end(), L"oParameterDisplay已存在",L"GDMPLab",L"2024-03-30");

    m_uidToParameterDisplayMap[uid] = TransferOwnership(oParameterDisplay);
    return true;
}

IParameterDisplay* gcmp::ParameterDisplayManager::GetParameterDisplay( const UniIdentity& uid )
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pDoc, L"m_pDoc为空！",L"GDMPLab",L"2024-03-30");

    auto itBuiltIn = BuiltInUidToParameterDisplayMap().find(uid);
    if(itBuiltIn != BuiltInUidToParameterDisplayMap().end())
        return itBuiltIn->second.get();

    auto it = m_uidToParameterDisplayMap.find(uid);
    if(it != m_uidToParameterDisplayMap.end())
        return it->second.get();

    const IParameterDefinitionLibrary* paramLib = IParameterDefinitionLibrary::Get(m_pDoc.Get());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(paramLib, L"paramLib为空！",L"GDMPLab",L"2024-03-30");

    const IParameterDefinition* paramDef = paramLib->GetParameterDefinitionByUid(uid);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(paramDef, L"paramDef为空！",L"GDMPLab",L"2024-03-30");

    IParameterDisplayCreator parameterDisplayCreator = IParameterDisplayManager::GetParameterDisplayCreator();
    if (parameterDisplayCreator != nullptr)
    {
        OwnerPtr<IParameterDisplay> opParamDisplay = parameterDisplayCreator(m_pDoc.Get(), paramDef);
        if (opParamDisplay)
        {
            m_uidToParameterDisplayMap[uid] = TransferOwnership(opParamDisplay);
            return m_uidToParameterDisplayMap[uid].get();
        }
    }

    UniIdentity ptId = paramDef->GetParameterTypeId();
    if (ptId == PARAMETER_TYPE(None) || ptId == PARAMETER_TYPE(Length) || ptId == PARAMETER_TYPE(Angle) ||
        ptId == PARAMETER_TYPE(Number) || ptId == PARAMETER_TYPE(Text) || ptId == PARAMETER_TYPE(Float) ||
        ptId == PARAMETER_TYPE(Area) || ptId == PARAMETER_TYPE(Volume))
    {
        m_uidToParameterDisplayMap[uid] = IParameterDisplay::CreateParameterDisplayEditbox(uid);
        return m_uidToParameterDisplayMap[uid].get();
    }
    else if (ptId == PARAMETER_TYPE(Material))
    {
        if (auto valueList = paramDef->GetValueList())
        {
            m_uidToParameterDisplayMap[uid] = IParameterDisplay::CreateParameterDisplayDropdownList(uid, TransferOwnership(valueList->Clone()));
            return m_uidToParameterDisplayMap[uid].get();
        }
    }
    else if (ptId == PARAMETER_TYPE(YesNo))
    {
        m_uidToParameterDisplayMap[uid] = IParameterDisplay::CreateParameterDisplayCheckbox(uid);
        return m_uidToParameterDisplayMap[uid].get();
    }
    else if (ptId == PARAMETER_TYPE(ValueList))
    {
        if (auto valueList = paramDef->GetValueList())
        {
            m_uidToParameterDisplayMap[uid] = IParameterDisplay::CreateParameterDisplayDropdownList(uid, TransferOwnership(valueList->Clone()));
            return m_uidToParameterDisplayMap[uid].get();
        }
    }
    else if (ptId == PARAMETER_TYPE(StandardCodeReference))
    {
        m_uidToParameterDisplayMap[uid] = IParameterDisplay::CreateParameterDisplayEditbox(uid);
        return m_uidToParameterDisplayMap[uid].get();
    }
    else if (ptId == PARAMETER_TYPE(Custom))
    {
        return nullptr;
    }
    else if (ptId == PARAMETER_TYPE(Color))
    {
        return nullptr;
    }
    else if (ptId == PARAMETER_TYPE(TextStyle))
    {
        return m_uidToParameterDisplayMap[uid].get();
    }
    else
    {
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(false, L"未处理类型！",L"GDMPLab",L"2024-03-30");
    }

    return nullptr;
}

IParameterDisplay* gcmp::ParameterDisplayManager::GetParameterDisplay(const IParameterDefinition* pParamDef)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pParamDef, L"pParamDef为空",L"GDMPLab",L"2024-03-30");

    UniIdentity uid;
    if (pParamDef->IsStandard())
    {
        const IParameterDefinitionLibrary* pParaDefLib = IParameterDefinitionLibrary::Get(m_pDoc.Get());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pParaDefLib, L"pParaDefLib为空",L"GDMPLab",L"2024-03-30");
        int paramId = pParaDefLib->GetParameterDefinitionIdByStandardCode(pParamDef->GetStandardCode());
        uid = pParaDefLib->GetParameterDefinitionUidById(paramId);
    }
    else
    {
        uid = pParamDef->GetUid();
    }

    return GetParameterDisplay(uid);
}

bool gcmp::ParameterDisplayManager::DeleteParameterDisplay(const UniIdentity& uid)
{
    auto itBuiltIn = BuiltInUidToParameterDisplayMap().find(uid);
    if (itBuiltIn != BuiltInUidToParameterDisplayMap().end())
        return false;

    auto it = m_uidToParameterDisplayMap.find(uid);
    if (it != m_uidToParameterDisplayMap.end())
        m_uidToParameterDisplayMap.erase(it);

    return true;
}

const IDocument* gcmp::ParameterDisplayManager::GetDocument() const
{
    return m_pDoc.Get();
}
